package gateway.mgt.api

import com.amihaiemil.camel.YamlSequenceBuilder
import grails.gorm.dirty.checking.DirtyCheck
import grails.validation.Validateable
import groovy.transform.ToString

//import grails.rest.Resource
import org.springframework.validation.FieldError

//@Resource(uri = "/apiInOutParam")
class ApiInOutParam implements ApiDefinition.Pluggable {

    static enum Scope {
        Query, Path, Header
    }

    static enum Type {
        String, Integer, Long, Float, Double, Boolean
    }

    @DirtyCheck
    @ToString(includePackage = false, includes = ["method", "name"])
    static class Location implements Validateable {
        Scope scope
        String name

        static constraints = {
            scope(nullable: false)
            name(blank: false)
        }
    }

    Integer order

    Type type
    String defaultValue

    Location atRequest
    Location atBackend

    Date dateCreated
    Date lastUpdated

    static embedded = ['atRequest', 'atBackend']

    static belongsTo = [apiDefinition: ApiDefinition]

    String description

    static constraints = {
        apiDefinition(nullable: false)
        order(nullable: false, min: 1, unique: "apiDefinition")
        type(nullable: false)
        atRequest(nullable: false, validator: { Location val, def obj, def errors ->
            boolean valid = val.validate()
            if (!valid) {
                val.errors.allErrors.each { FieldError error ->
                    final String field = "atRequest"
                    final String code = "$error.code"
                    errors.rejectValue(field, code, error.arguments, error.defaultMessage)
                }
            }
            return valid
        })
        atBackend(nullable: true, validator: { Location val, def obj, def errors ->
            boolean valid = val?.validate()
            if (!valid && val) {
                val.errors.allErrors.each { FieldError error ->
                    final String field = "atBackend"
                    final String code = "$error.code"
                    errors.rejectValue(field, code, error.arguments, error.defaultMessage)
                }
            }
            return valid
        })
        defaultValue(nullable: true, validator: { val, obj -> obj.atBackend || obj.atBackend == null && val == null })
        description(nullable: true, maxSize: 200, widget: 'textarea')
        dateCreated()
        lastUpdated()
    }

    static mapping = {
        order column: "_order"
    }

    private static enum Action {
        Add, Remove, Transfer, Modify
    }

    private Action getProcessAction() {
        if (!atRequest.name && atBackend.name) {
            Action.Add
        } else if (atRequest.name && !atBackend?.name) {
            Action.Remove
        } else if (atRequest.name == atBackend.name && atRequest.scope == atBackend.scope) {
            Action.Transfer
        } else if (atRequest.name != atBackend.name || atRequest.scope != atBackend.scope) {
            Action.Modify
        }
    }

    @Override
    void plug(Map<String, YamlSequenceBuilder> routeBuildElements, final ApiDefinition current) {
        switch ("${processAction}-${atRequest?.scope}-${atBackend?.scope}" as String) {
            case "${ApiInOutParam.Action.Remove}-${Scope.Header}-${null}" as String:
                routeBuildElements.filters = routeBuildElements.filters.add("RemoveRequestHeader=$atRequest.name")
                break
            case "${ApiInOutParam.Action.Modify}" as String:
                //generate custom filter expression
                break
            case "${ApiInOutParam.Action.Transfer}" as String:
                /*ignore*/
                break
        }
    }
}
